import os
import requests
import json
import time
import hmac
import hashlib
import urllib.parse
import base64
import logging
from flask import Flask, request, jsonify
from flask_cors import CORS

# 创建Flask应用
app = Flask(__name__)
CORS(app, resources={r"/publish_abnormal": {"origins": "*"}})
# 允许所有域访问

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(),  # 输出到控制台
        logging.FileHandler('app.log')  # 输出到文件
    ]
)

# 钉钉机器人配置
DINGTALK_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=b8043ac4f020b5d8657fb265e88e4c8da8283ee555cc21b41a21635e79924e92"
DINGTALK_SECRET = "SEC848ad20cee9340d2c6775a28166672f12b942dd1b34edcfb59443a9f18be0fac"  # 如果有加签安全设置
HEADERS = {"Content-Type": "application/json"}

# 异常类型映射表
ABNORMAL_MAP = {
    "1": "烟火异常",
    "2": "非法入侵",
    "3": "设备故障",
    "4": "人员聚集",
    "5": "车辆违停"
}


@app.route('/publish_abnormal', methods=['GET', 'POST'])
def publish_abnormal():
    """
    接收前端发送的异常数据并发送到钉钉
    支持多种参数传递方式: GET参数、POST表单、POST JSON
    """
    try:
        logging.info(f"收到请求: 方法={request.method}, 内容类型={request.content_type}")

        # 获取参数 'abnormalities'，支持多种方式
        # abnormalities_data = (
        #         request.args.get('abnormalities') or
        #         request.form.get('abnormalities') or
        #         (request.get_json() or {}).get('abnormalities')
        # )
        abnormalities_data = request.data

        logging.info(f"接收到的abnormalities参数类型: {type(abnormalities_data)}, 内容: {abnormalities_data}")

        if not abnormalities_data:
            logging.error("缺少 'abnormalities' 参数")
            return jsonify({
                "status": "error",
                "message": "缺少 'abnormalities' 参数"
            }), 400

        # 如果数据是字符串，尝试解析为JSON
        if isinstance(abnormalities_data, str):
            try:
                abnormalities = json.loads(abnormalities_data)
            except json.JSONDecodeError:
                logging.error("abnormalities 参数不是有效的JSON格式")
                return jsonify({
                    "status": "error",
                    "message": "abnormalities 参数不是有效的JSON格式"
                }), 400
        else:
            abnormalities = abnormalities_data

        # 确保 abnormalities 是列表
        if not isinstance(abnormalities, list):
            abnormalities = [abnormalities]

        logging.info(f"处理后 abnormalities 类型: {type(abnormalities)}, 长度: {len(abnormalities)}")

        # 处理异常数据
        processed_abnormalities = process_abnormalities(abnormalities)

        if processed_abnormalities:
            logging.info(f"准备发送 {len(processed_abnormalities)} 条异常记录到钉钉")
            send_dingtalk_notification(processed_abnormalities)

            return jsonify({
                "status": "success",
                "message": f"成功发送 {len(processed_abnormalities)} 条异常记录到钉钉"
            })
        else:
            logging.warning("未发现有效的异常记录")
            return jsonify({
                "status": "warning",
                "message": "未发现有效的异常记录"
            })

    except Exception as e:
        logging.error(f"处理异常数据时出错: {str(e)}")
        import traceback
        logging.error(traceback.format_exc())
        return jsonify({
            "status": "error",
            "message": f"处理异常数据时出错: {str(e)}"
        }), 500


def process_abnormalities(abnormalities):
    """
    处理前端发送的异常数据
    :param abnormalities: 异常数据列表，每个元素可以是字典、列表或字符串
    """
    processed_abnormalities = []

    logging.info(f"开始处理异常数据，共 {len(abnormalities)} 条记录")

    for i, abnormality in enumerate(abnormalities):
        logging.info(f"处理第 {i + 1} 条记录: 类型={type(abnormality)}, 内容={abnormality}")
        json_str = abnormality.decode('utf-8')
        abnormality = json.loads(json_str)[0]
        print(abnormality, type(abnormality), isinstance(abnormality, dict))

        # 处理字符串格式的异常数据
        if isinstance(abnormality, str):
            parts = abnormality.strip().split()
            if len(parts) < 5:
                logging.warning(f"忽略无效行: {abnormality}")
                continue

            time_str = parts[0]
            lon = parts[1]
            lat = parts[2]
            alt = parts[3]
            category = parts[4]

            processed_abnormalities.append({
                "time": time_str,
                "longitude": lon,
                "latitude": lat,
                "altitude": alt,
                "category": category
            })

        # 处理字典格式的异常数据
        elif isinstance(abnormality, dict):
            if all(key in abnormality for key in ["time", "Lng", "Lat", "hight", "number"]):
                processed_abnormalities.append(abnormality)
            else:
                logging.warning(f"忽略无效的异常数据: {abnormality}")

        # 处理列表/数组格式的异常数据
        elif isinstance(abnormality, list):
            if len(abnormality) >= 5:
                processed_abnormalities.append({
                    "time": str(abnormality[0]),
                    "longitude": str(abnormality[1]),
                    "latitude": str(abnormality[2]),
                    "altitude": str(abnormality[3]),
                    "category": str(abnormality[4])
                })
            else:
                logging.warning(f"忽略无效的列表格式异常数据: {abnormality}")

        # 处理其他类型的数据
        else:
            logging.warning(f"忽略未知类型的异常数据: {type(abnormality)} - {abnormality}")

    logging.info(f"处理完成，有效记录数: {len(processed_abnormalities)}")
    return processed_abnormalities


def format_abnormality_message(abnormality):
    """
    格式化异常数据为消息文本
    """
    # 添加类型检查，确保 abnormality 是字典
    if not isinstance(abnormality, dict):
        logging.warning(f"format_abnormality_message 收到非字典类型数据: {type(abnormality)} - {abnormality}")
        return f"无效的异常数据格式: {abnormality}"

    time_str = abnormality.get("time", "")
    lon = float(abnormality.get("Lng", ""))
    lat = float(abnormality.get("Lat", ""))
    alt = float(abnormality.get("hight", ""))
    category = abnormality.get("number", "")

    # 格式化时间
    formatted_time = format_time(time_str)

    # 创建地图链接
    map_link = f"https://uri.amap.com/marker?position={lon},{lat}"

    # 格式化消息
    return (
        f"**时间**: {formatted_time}\n"
        f"**位置**: [经度={lon}, 纬度={lat}]({map_link})\n"
        f"**海拔**: {alt}米\n"
        f"**异常类型**: {ABNORMAL_MAP.get(category, '未知异常')}"
    )


def format_time(time_str):
    """格式化时间戳 (示例: 20250710152435 -> 2025-07-10 15:24:35)"""
    if len(time_str) >= 14:
        return f"{time_str[:4]}-{time_str[4:6]}-{time_str[6:8]} {time_str[8:10]}:{time_str[10:12]}:{time_str[12:14]}"
    return time_str  # 如果格式不正确，返回原始字符串


def send_dingtalk_notification(abnormalities):
    """通过钉钉机器人发送通知"""
    logging.info(f"开始处理 {len(abnormalities)} 条异常记录")

    # 格式化所有异常消息
    messages = []
    for ab in abnormalities:
        try:
            message = format_abnormality_message(ab)
            messages.append(message)
        except Exception as e:
            logging.error(f"格式化异常消息时出错: {str(e)}")
            messages.append(f"格式化异常消息时出错: {str(ab)}")

    logging.info(f"格式化后的消息数量: {len(messages)}")

    # 限制消息数量，避免超过钉钉限制
    if len(messages) > 10:
        messages = messages[:10]
        messages.append("**还有更多异常记录未显示...**")

    content = "### 🚨 智能视频分析警报\n\n" + "\n\n---\n\n".join(messages)
    # logging.info(f"最终消息内容: {content}")

    payload = {
        "msgtype": "markdown",
        "markdown": {
            "title": "智能视频分析警报",
            "text": content
        },
        "at": {
            "isAtAll": False
        }
    }

    try:
        # 如果有加签安全设置
        if DINGTALK_SECRET:
            timestamp = str(round(time.time() * 1000))
            secret_enc = DINGTALK_SECRET.encode('utf-8')
            string_to_sign = f"{timestamp}\n{DINGTALK_SECRET}"
            string_to_sign_enc = string_to_sign.encode('utf-8')
            hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
            sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
            webhook_url = f"{DINGTALK_WEBHOOK}&timestamp={timestamp}&sign={sign}"
        else:
            webhook_url = DINGTALK_WEBHOOK

        response = requests.post(
            webhook_url,
            headers=HEADERS,
            data=json.dumps(payload),
            timeout=10
        )

        if response.status_code == 200:
            result = response.json()
            if result.get('errcode') == 0:
                logging.info(f"钉钉通知发送成功，共发送 {len(abnormalities)} 条异常记录")
            else:
                logging.error(f"钉钉接口返回错误: {result.get('errmsg')}")
        else:
            logging.error(f"钉钉消息发送失败: HTTP {response.status_code} - {response.text}")
    except Exception as e:
        logging.error(f"发送钉钉通知时出错: {str(e)}")


if __name__ == "__main__":
    # 启动Flask应用
    app.run(host='0.0.0.0', port=5000, debug=True)